#pragma once
#include <iostream>
#include <functional>
#include <unordered_map>
#include "Epoller.hpp"
#include "logMessage.hpp"
#include "protocal.hpp"
#include "Sock.hpp"
#include "Util.hpp"
const int default_port = 8080;
class Connection;
class TcpServer;
using func_t = function<void(Connection *)>;
class Connection
{
public:
    Connection(int sock, TcpServer *tsp) : _sock(sock), _tsp(tsp)
    {
    }
    ~Connection()
    {
    }
    void Register(func_t recver, func_t sender, func_t exceper)
    {
        _recver = recver;
        _sender = sender;
        _exceper = exceper;
    }
    void Close()
    {
        close(_sock);
    }

public:
    int _sock;
    // 输入缓冲区和输出缓冲区
    string _inbuffer;
    string _outbuffer;

    func_t _recver;  // 从sock读
    func_t _sender;  // 向sock写
    func_t _exceper; // 处理异常
    TcpServer *_tsp;
};
class TcpServer
{
public:
    TcpServer(func_t func) : _port(default_port), _func(func)
    {
    }
    ~TcpServer()
    {
    }
    void InitServer()
    {
        _sock.Socket();
        _sock.Bind(_port);
        _sock.Listen();
        // 把listensort加入epoll
        _rev = new epoll_event[size];
        _epoller.Create();
        // 加入之前需要将fd设置为非阻塞fd
        // epoller.Add_In_fd(_sock.fd());
        // bind(Accepter,this,placeholders::_1) ?????
        // 创建了一个绑定了成员函数的可调用对象，用于延迟执行函数调用并在需要时传递给其他部分进行使用
        AddConnect(_sock.fd(), EPOLLIN | EPOLLET, std::bind(&TcpServer::Accepter, this, placeholders::_1), nullptr, nullptr);
    }
    // 事件分发器
    void Dispatcher()
    {
        while (1)
        {
            int timeout = 1000;
            loop(timeout);
            logMessage(NORMAL, "timeout ..");
        }
    }
    bool IsConnectionExist(int sock)
    {
        // 判断Connect存不存在
        auto it = Connect_map.find(sock);
        return it != Connect_map.end();
    }
    void EnableReaderWriter(Connection *cnn, bool reader, bool writer)
    {
        uint32_t events;
        events = (reader ? EPOLLIN : 0) | (writer ? EPOLLOUT : 0) | EPOLLET;
        _epoller.Control(cnn->_sock, events, EPOLL_CTL_MOD);
    }
    void loop(int timeout)
    {
        // 进行wait，并处理不是异常的异常，EPOLLERR EPOLLHUP都将当作读写进行处理
        int n = _epoller.Wait(_rev, size, timeout); // 获取就绪的事件
        cout << n << endl;
        for (int i = 0; i < n; i++)
        {
            int sock = _rev[i].data.fd;
            uint16_t event = _rev[i].events;
            if ((event & EPOLLERR) || (event & EPOLLHUP))
                event |= EPOLLIN | EPOLLOUT;
            logMessage(NORMAL, "sock :%d,event : %d", sock, event);
            // 第三个参数确保上层有写recver sender函数
            if ((event & EPOLLIN) && IsConnectionExist(sock) && Connect_map[sock]->_recver)
            {
                Connect_map[sock]->_recver(Connect_map[sock]);
            }
            else if ((event & EPOLLOUT) && IsConnectionExist(sock) && Connect_map[sock]->_sender)
            {
                Connect_map[sock]->_sender(Connect_map[sock]);
            }
        }
    }

    void Accepter(Connection *cnn)
    {
        // 重复进行accept，并添加进epoll帮我管理
        // EAGAIN 是指没有数据可读
        // EWOULDBLOCK 被阻塞
        // EINTER 是被中断时由accept抛出
        // 判断accept异常，若不是异常就退出
        while (1)
        {
            string clientip;
            uint16_t clientport;
            int err;
            int sock = _sock.Accept(&clientip, &clientport, &err);
            logMessage(NORMAL, "accept errno :%d", err);

            if (sock > 0)
            {
                AddConnect(sock, EPOLLIN | EPOLLET,
                           bind(&TcpServer::Recver, this, placeholders::_1),
                           bind(&TcpServer::Sender, this, placeholders::_1),
                           bind(&TcpServer::Excepter, this, placeholders::_1));
                logMessage(NORMAL, "accept success [%s][%d]", clientip.c_str(), clientport);
            }
            else
            {
                if (err == EAGAIN || err == EWOULDBLOCK)
                    break;
                else if (err == EINTR)
                    continue;
                else
                    break;
            }
        }
    }
    void Recver(Connection *cnn)
    {
        // 重复调用recv，判断不是异常的异常进行跳出
        char buffer[1024];
        while (1)
        {
            int n = recv(cnn->_sock, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                cnn->_inbuffer += buffer;
            }
            else if (n == 0)
            {
                if (cnn->_exceper)
                    cnn->_exceper(cnn);
                return;
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    if (cnn->_exceper)
                        cnn->_exceper(cnn);
                    return;
                }
            }
        }
        // logMessage(NORMAL,"[%d] -> %s",cnn->_sock,cnn->_inbuffer.c_str());
        // 将收到的报文进行处理
        _func(cnn);
    }
    void Sender(Connection *cnn)
    {
        // 将在输出缓冲区的东西发送出去
        while (1)
        {
            ssize_t n = send(cnn->_sock, cnn->_outbuffer.c_str(), cnn->_outbuffer.size(), 0);
            logMessage(NORMAL,"cnn输出缓冲区是否空 %d",cnn->_outbuffer.empty());
            if (n >= 0 && errno == 0)
            {
                logMessage(NORMAL, "开始发送");
                if (cnn->_outbuffer.empty())
                {
                    //EnableReaderWriter(cnn, true, false);
                    logMessage(NORMAL, "清空输出缓冲区");
                    break;
                }
                else
                {
                    cnn->_outbuffer.erase(0,n);
                    logMessage(NORMAL, "发送了%d 个字符", n);
                }
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    if (cnn->_exceper)
                    {
                        cnn->_exceper(cnn);
                        return;
                    }
                }
            }
        }
        // 发完信息及时将send从epoll中剔除
        if (!cnn->_outbuffer.empty())
            EnableReaderWriter(cnn, true, true);
        else
            EnableReaderWriter(cnn, true, false);
    }
    void Excepter(Connection *cnn)
    {
        logMessage(NORMAL, "Excepter in");
        _epoller.Control(cnn->_sock,0,EPOLL_CTL_DEL);
        Connect_map.erase(cnn->_sock);
        logMessage(NORMAL, "%d 标识符已经关闭");
        cnn->Close();
        delete cnn;
    }
    void AddConnect(int sock, uint32_t event, func_t recver, func_t sender, func_t exceper)
    {
        // 将fd设为非阻塞
        if (event & EPOLLET)
            Util::SetNotBlock(sock);
        // 给对应的sork设置对应回调处理方法
        Connection *cnn = new Connection(sock, this);
        cnn->Register(recver, sender, exceper);
        // 将sock加入到epoll中让他帮我关心
        _epoller.Add_Event(sock,event);
        // 将Connect管理起来
        Connect_map.insert(pair<int, Connection *>(sock, cnn));
    }

private:
    // sock 中维护了一个listensort
    Sock _sock;
    uint16_t _port;
    Epoller _epoller;
    struct epoll_event *_rev;
    func_t _func;
    // Connection管理的是一个连接的输入输出缓冲区，所以Connection会很多，需要管理起来
    unordered_map<int, Connection *> Connect_map;
};